﻿using HartConfigTool.HARTCommands;
using HartConfigTool.HARTCommands.CMDs;
using HartConfigTool.SerialPortUtil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HartConfigTool.CommandsQueue
{
    internal class CMDsQueue
    {
        private SerialPortsManager _serialPortsManager;
        private readonly Queue<(ICommand Command, TimeSpan Delay)> _commandQueue = new Queue<(ICommand Command, TimeSpan Delay)>();
        private bool _isRunning;
        private CancellationTokenSource _cts;
        public CMDsQueue(SerialPortsManager serialPortsManager) 
        { 
            this._serialPortsManager = serialPortsManager;
            this._serialPortsManager.CommandCompleted += OnCommandCompleted;
        }
        public void Start()
        {
            if (!_isRunning)
            { 
                ExecuteNextCommand();
            }
        }
        private async void ExecuteNextCommand()
        {
            if (_commandQueue.Count == 0)
            {
                _isRunning = false;
                return;
            }

            _isRunning = true;

            var (command, delay) = _commandQueue.Dequeue();
            _serialPortsManager.SetCurrentCMD(command);

            _cts = new CancellationTokenSource();
            var commandTask = command.ExecuteCMD();
            var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5), _cts.Token);

            var completedTask = Task.WhenAll(commandTask, timeoutTask);

            if (completedTask == timeoutTask)
            {
                // Command timed out
                //_serialPortsManager.debugTextBox.Invoke(new Action (() => _serialPortsManager.debugTextBox.AppendText("Command timed out.\r\n")));
            }
            else
            {
               // _serialPortsManager.debugTextBox.Invoke(new Action(() => _serialPortsManager.debugTextBox.AppendText("command Execute completed.\r\n")));
                await WaitForResponseAndValidateAysnc(command);
            }

            await Task.Delay(delay);
            ExecuteNextCommand();
        }
        private async Task WaitForResponseAndValidateAysnc(ICommand command)
        { 
            var tcs = new TaskCompletionSource<bool>();
            EventHandler handler = (s, e) => tcs.TrySetResult(true);

            try
            {
                _serialPortsManager.CommandCompleted += handler;

                var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
                var responseTask = tcs.Task;

                var completedTask = await Task.WhenAny(responseTask, timeoutTask);

                if (completedTask == timeoutTask)
                {
                    // No response received within the timeout period
                    //_serialPortsManager.debugTextBox.Invoke(new Action(() => _serialPortsManager.debugTextBox.AppendText("WhenAny 3.\r\n")));
                }
                else 
                {
                    if (command is CMD0ReadUniqueIdentifier)
                    {
                       // _commandQueue.Clear();
                    }
                    //_serialPortsManager.debugTextBox.Invoke(new Action(() => _serialPortsManager.debugTextBox.AppendText("WhenAny 4.\r\n")));
                    // Response received, validate it
                    //if (command.IsCompleted)
                    {
                       // _commandQueue.Clear();
                    }
                    //else
                    { 
                    
                    }
                }
            }
            finally
            { 
                _serialPortsManager.CommandCompleted -= handler;
            }
        }
        public void EnqueueCommand(ICommand command, TimeSpan delay)
        {
            _commandQueue.Enqueue((command, delay));
        }
        private void OnCommandCompleted(object sender, EventArgs e)
        {
            // Notify that the command has completed and proceed to the next command
            _cts?.Cancel();
        }
    }
}
